package com.smartian.v2.filters.impl;

import android.text.TextUtils;


import com.smartian.v2.AbstractTextParser;
import com.smartian.v2.TextPattern;
import com.smartian.v2.filters.IDateTimeNodeInterceptor;
import com.smartian.v2.model.DateTimeNode;
import com.smartian.v2.utils.DateTimeHelper;
import com.smartian.v2.utils.LunarCalendarUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;

/**
 * Created by tianweitong on 2020/4/10.
 */

public class LunnarDateInterceptor implements IDateTimeNodeInterceptor {

    @Override
    public List<DateTimeNode> handleOnIntercept(AbstractTextParser textParser, int repeatType, List<DateTimeNode> dateTimeNodes) {
        if(textParser==null){
            return dateTimeNodes;
        }

        if(dateTimeNodes==null){
            dateTimeNodes = new ArrayList<>();
        }

        String sourceText = textParser.getSourceText();
        Matcher matcher =  null;

        for (int i=0;i<TextPattern.PATTERN_LOCATOR_LUNAR.length;i++) {

            matcher = TextPattern.PATTERN_LOCATOR_LUNAR[i].matcher(sourceText);
            lunarToSolarDateTimeCompute(dateTimeNodes, sourceText, matcher);
        }

        return dateTimeNodes;
    }

    private void lunarToSolarDateTimeCompute(List<DateTimeNode> dateTimeNodes, String sourceText, Matcher matcher) {
        Calendar calendar = Calendar.getInstance();
        int YEAR = calendar.get(Calendar.YEAR);
        int MONTH = calendar.get(Calendar.MONTH)+1;

        do{
            if(!matcher.find()) break;

            String groupText = matcher.group();
            int start = matcher.start();
            int year  = 0;

            if(groupText.contains(TextPattern.WORD_YEAY)){
                DateTimeNode dateTimeNode = DateTimeHelper.tryGetYearNode(sourceText);
                if(dateTimeNode.index>=0){
                    year = DateTimeHelper.getIntegerValue(dateTimeNode.resultText);
                }
            }

            String transText = DateTimeHelper.replaceChineseNumberToArbirc(groupText);

            Matcher monthMatcher = TextPattern.PATTERN_CURRENT_MONTH.matcher(transText);
            while(monthMatcher.find()){
                String monthText = monthMatcher.group();
                transText = transText.replaceAll(monthText,MONTH+ TextPattern.WORD_MONTH);
            }

            monthMatcher = TextPattern.PATTERN_NEXT_MONTH.matcher(transText);
            while(monthMatcher.find()){
                String monthText = monthMatcher.group();
                transText = transText.replaceAll(monthText,(MONTH+1)+ TextPattern.WORD_MONTH);
            }

            monthMatcher = TextPattern.PATTERN_NEXT_NEXT_MONTH.matcher(transText);
            while(monthMatcher.find()){
                String monthText = monthMatcher.group();
                transText = transText.replaceAll(monthText,(MONTH+2)+ TextPattern.WORD_MONTH);
            }

            monthMatcher = TextPattern.PATTERN_LAST_MONTH.matcher(transText);
            while(monthMatcher.find()){
                String monthText = monthMatcher.group();
                transText = transText.replaceAll(monthText,(MONTH-1)+ TextPattern.WORD_MONTH);
            }

            String monthStr = DateTimeHelper.readPrevNumberAtFlag(transText, TextPattern.WORD_MONTH);

            int month = DateTimeHelper.getIntegerValue(monthStr);
            int day = 0;


            boolean shouldHandleWidthSolar = transText.contains(TextPattern.WORD_START) && !transText.endsWith(TextPattern.WORD_START);

            if(shouldHandleWidthSolar){
                    String dayStr  = DateTimeHelper.readNextNumberAtFlag(transText, TextPattern.WORD_START);
                    int lunarDay = DateTimeHelper.getIntegerValue(dayStr);
                    Calendar sloarCalendar = getSloarCalendar(year,month,lunarDay);
                    if(sloarCalendar==null) {
                        break;
                    }
                    day = sloarCalendar.get(Calendar.DAY_OF_MONTH);
                    month = sloarCalendar.get(Calendar.MONTH)+1;
                    year = sloarCalendar.get(Calendar.YEAR);
            }else {
                if (transText.endsWith(TextPattern.WORD_START) ) {
                    day = 1;
                }

                if (transText.endsWith(TextPattern.WORD_MIDDLE_1) || transText.endsWith(TextPattern.WORD_MIDDLE_2)) {
                    day = 15;
                }
                if (transText.endsWith(TextPattern.WORD_END_1) || transText.endsWith(TextPattern.WORD_END_2)) {
                    int y = year > 0 ? year : YEAR;

                    if (DateTimeHelper.has31Day(month)) {
                        day = 31;
                    } else {
                        if (month == 2) {
                            if (DateTimeHelper.isLeapYear(y)) {
                                day = 29;
                            } else {
                                day = 28;
                            }
                        } else {
                            day = 30;
                        }
                    }
                }

            }

            String  locatorText = "";
            Matcher lunarMatcher = TextPattern.PATTERN_LUNAR.matcher(transText);
            if(lunarMatcher.find()){
                String name = lunarMatcher.group();
                int startIndex = lunarMatcher.start();
                if(startIndex<=(start +groupText.length()) ){
                    locatorText = name;
                    break;
                }
            }

            if(!shouldHandleWidthSolar && !TextUtils.isEmpty(locatorText)){
                if(day>=30){
                    day = 29;
                }

                Calendar sloarCalendar = getSloarCalendar(year,month,day );
                if(sloarCalendar==null) {
                    break;
                }
                day = sloarCalendar.get(Calendar.DAY_OF_MONTH);
                month = sloarCalendar.get(Calendar.MONTH)+1;
                year = sloarCalendar.get(Calendar.YEAR);

            }

            if(year!=0){
                calendar.set(Calendar.YEAR,year);
            }

            calendar.set(Calendar.MONTH,month-1);
            calendar.set(Calendar.DAY_OF_MONTH,day);

            DateTimeNode dateNode = new DateTimeNode();
            dateNode.index = start;
            dateNode.locatorText = locatorText;
            dateNode.text = groupText;
            dateNode.type = DateTimeNode.TYPE_DATE;
            dateNode.resultText = TextPattern.sDateFormat.format(calendar.getTimeInMillis());

            DateTimeNode timeNode = DateTimeHelper.findBestDateNode(dateTimeNodes, DateTimeNode.TYPE_TIME);
            if(timeNode==null){
                String currentTime = DateTimeHelper.getCurrentTime();
                timeNode = new DateTimeNode();
                timeNode.text = "";
                timeNode.index = 0;
                timeNode.resultText = currentTime;
                timeNode.locatorText = "";
                timeNode.type = DateTimeNode.TYPE_TIME;

                dateTimeNodes.add(timeNode);
            }

            dateTimeNodes.add(dateNode);

        }while (true);
    }

    @Override
    public boolean isSupportedRepeatType(int repeatType) {
        return true;
    }

    private Calendar getSloarCalendar(int year, int month, int lunarDay) {
        Calendar calendar = Calendar.getInstance();

        int m = month - 1;
        int d = lunarDay;
        int y = 0;
        if(year<=0){
            y = calendar.get(Calendar.YEAR);
        }else{
            y = year;
        }
        int maxMonth  = month+14;

        for (;m<maxMonth;m++) {
            for (;d<31;d++) {
                int _maskMonth = m%12;
                if(_maskMonth==0){
                    _maskMonth=12;
                }
                LunarCalendarUtils.Solar solar = new LunarCalendarUtils.Solar(y, _maskMonth, d);
                LunarCalendarUtils.Lunar lunar = LunarCalendarUtils.solarToLunar(solar);

                if(lunar==null) continue;
                if(lunar.lunarMonth==month && lunar.lunarDay==lunarDay){
                    calendar.set(y, _maskMonth-1, d);
                    return calendar;
                }
            }
            d=0;
            if(year==-1 && m%12==0){
                y++;
            }
        }

        return null;
    }
}
